package cn.demo.um.service.impl;

import cn.demo.common.constant.CommonConstants;
import cn.demo.common.core.page.PageQuery;
import cn.demo.common.utils.*;
import cn.demo.um.domain.UmAttrConf;
import cn.demo.um.domain.UmAttrData;
import cn.demo.um.domain.UmClientUser;
import cn.demo.um.domain.UmUserFocus;
import cn.demo.um.mapper.UmAttrConfMapper;
import cn.demo.um.mapper.UmAttrDataMapper;
import cn.demo.um.mapper.UmClientUserMapper;
import cn.demo.um.mapper.UmUserFocusMapper;
import cn.demo.um.service.IUmAttrConfService;
import cn.demo.um.service.IUmAttrDataService;
import cn.demo.um.service.IUmClientUserService;
import cn.demo.um.support.Constant;
import cn.demo.um.support.drive.MatcherDrive;
import cn.demo.um.support.factory.MatcherDriveFactory;
import cn.demo.um.support.model.MatchScoreDto;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.demo.um.domain.UmClientUser.DELIMITER;
import static cn.demo.um.domain.table.UmAttrDataTableDef.UM_ATTR_DATA;
import static cn.demo.um.domain.table.UmUserFocusTableDef.UM_USER_FOCUS;

/**
 * 客户端用户Service业务层处理
 *
 * @author xtjun
 * @date 2024-06-06
 */
@Service
public class UmClientUserServiceImpl extends ServiceImpl<UmClientUserMapper, UmClientUser> implements IUmClientUserService {
    @Resource
    private UmClientUserMapper umClientUserMapper;
    @Resource
    private UmAttrDataMapper umAttrDataMapper;
    @Resource
    private UmAttrConfMapper umAttrConfMapper;
    @Resource
    private UmUserFocusMapper umUserFocusMapper;
    @Resource
    private IUmAttrConfService umAttrConfService;

    @Autowired
    private IUmAttrDataService umAttrDataService;
    @Autowired
    private MatcherDriveFactory matcherDriveFactory;

    /**
     * 查询客户端用户
     *
     * @param id 客户端用户主键
     * @return 客户端用户
     */
    @Override
    public UmClientUser selectUmClientUserById(String id) {
        return umClientUserMapper.selectOneWithRelationsById(id);
    }

    @Override
    public UmClientUser selectUserVoById(String id) {
        UmClientUser user = selectUmClientUserById(id);
        buildDict(user);
        return user;
    }

    @Override
    public void buildDict(List<UmClientUser> users) {
        if (CollectionUtils.isEmpty(users)) {
            return;
        }
        users.forEach(this::buildDict);
    }


    public void buildDict(UmClientUser user) {
        Map<String, UmAttrConf> attrConfMap = umAttrConfService.selectUmAttrConfAll().stream().collect(Collectors.toMap(UmAttrConf::getAttrCode, Function.identity()));
        if (null != user && CollectionUtils.isNotEmpty(user.getAttrDataList())) {
            Map<String, Object> attrDataMap = user.getAttrDataMap();
            for (UmAttrData umAttrData : user.getAttrDataList()) {
                UmAttrConf attrConf = attrConfMap.get(umAttrData.getAttrCode().replace(UmAttrConf.CONDITION_PREFIX, ""));
                if (null != attrConf) {
                    if (StringUtils.isNotEmpty(attrConf.getDictType())) {
                        String strKey = umAttrData.getAttrCode() + "_str";
                        String strLabel = DictUtils.getDictLabel(attrConf.getDictType(), umAttrData.getAttrValue());
                        attrDataMap.merge(strKey, strLabel, (a, b) -> a + DELIMITER + b);
                    } else if (CommonConstants.YES.equals(umAttrData.getIsStandard())) {
                        String strKey = umAttrData.getAttrCode() + "_str";
                        String strLabel = umAttrData.getAttrValue();
                        attrDataMap.merge(strKey, strLabel, (a, b) -> a + "-" + b);
                    }
                }
            }
        }
    }

    /**
     * 查询客户端用户列表
     *
     * @param umClientUser 客户端用户
     * @return 客户端用户
     */
    @Override
    public Page<UmClientUser> selectUmClientUserPage(UmClientUser umClientUser, PageQuery pageQuery) {
        QueryWrapper queryWrapper = QueryWrapper.create(umClientUser, UmClientUser.operators).orderBy(pageQuery.getOrderByColumn(), pageQuery.isAsc());
        SubQw subQw = getSubQw(umClientUser.getSearchValue(), umClientUser.getAttrQueryMap());
        if (subQw.flag()) {
            queryWrapper.in("id", subQw.subQueryWrapper());
        }
        return umClientUserMapper.paginateWithRelations(pageQuery.build(), queryWrapper);
    }

    private record SubQw(boolean flag, QueryWrapper subQueryWrapper) {
    }

    private static SubQw getSubQw(String searchValue, Map<String, String> attrQueryMap) {
        AtomicReference<Boolean> flag = new AtomicReference<>(false);
        List<String> selects = new ArrayList<>();
        List<String> having1 = new ArrayList<>();
        List<String> having2 = new ArrayList<>();
        List<String> codes = new ArrayList<>();
        selects.add("user_id");
        if (StringUtils.isNotEmpty(searchValue)) {
            flag.set(true);
            selects.add("sum(if(attr_code = 'XM' AND attr_value like '%" + searchValue + "%', 1, 0)) AS XM_Search_Count");
            selects.add("sum(if(attr_code = 'NC' AND attr_value like '%" + searchValue + "%', 1, 0)) AS NC_Search_Count");
            having1.add("XM_Search_Count > 0");
            having1.add("NC_Search_Count > 0");
            codes.add("XM");
            codes.add("NC");
        }
        if (ObjUtils.isNotEmpty(attrQueryMap)) {
            attrQueryMap.forEach((k, v) -> {
                if (StringUtils.isNotEmpty(v)) {
                    codes.add(k);
                    flag.set(true);
                    if (v.contains("-")) {
                        String[] split = v.split(",");
                        String where = "";
                        for (int i = 0; i < split.length; i++) {
                            String[] s = split[i].split("-");
                            where += "(attr_code = '" + k + "' AND attr_value between " + s[0] + " and " + s[1] + ")";
                            if (i < split.length - 1) {
                                where += " or ";
                            }
                        }
                        selects.add("sum(if(" + where + ", 1, 0)) AS " + k + "_Count");

                    } else {
                        selects.add("sum(if(attr_code = '" + k + "' AND attr_value in (" + v + "), 1, 0)) AS " + k + "_Count");

                    }
                    having2.add(k + "_Count > 0");
                }

            });

        }
        QueryWrapper subQueryWrapper = QueryWrapper.create().select(selects.toArray(String[]::new)).from(UM_ATTR_DATA).groupBy(UM_ATTR_DATA.USER_ID);
        QueryCondition queryCondition = QueryCondition.createEmpty();
        if (CollectionUtils.isNotEmpty(having1)) {
            queryCondition.and(QueryCondition.createEmpty().and(CollectionUtils.join(having1, " or ")));
        }
        if (CollectionUtils.isNotEmpty(having2)) {
            queryCondition.and(CollectionUtils.join(having2, " and "));
        }
        if (CollectionUtils.isNotEmpty(codes)) {
            subQueryWrapper.where(UM_ATTR_DATA.ATTR_CODE.in(codes));
        }
        subQueryWrapper.having(queryCondition);
        return new SubQw(flag.get(), QueryWrapper.create().select("user_id").from(subQueryWrapper).as("subQw"));
    }


    @Override
    public List<UmClientUser> selectUmClientUserList(UmClientUser umClientUser) {
        return umClientUserMapper.selectListWithRelationsByQuery(QueryWrapper.create(umClientUser, UmClientUser.operators));
    }

    /**
     * 新增客户端用户
     *
     * @param umClientUser 客户端用户
     * @return 结果
     */
    @Transactional
    @Override
    public int insertUmClientUser(UmClientUser umClientUser) {
        int rows = umClientUserMapper.insert(umClientUser);
        insertUmAttrData(umClientUser);
        return rows;
    }

    /**
     * 修改客户端用户
     *
     * @param umClientUser 客户端用户
     * @return 结果
     */
    @Transactional
    @Override
    public int updateUmClientUser(UmClientUser umClientUser) {
        if (CollectionUtils.isNotEmpty(umClientUser.getAttrDataList())) {
            umAttrDataMapper.deleteByQuery(QueryWrapper.create().eq(UmAttrData::getUserId, umClientUser.getId()));
            insertUmAttrData(umClientUser);
        }
        return umClientUserMapper.update(umClientUser);
    }

    /**
     * 批量删除客户端用户
     *
     * @param ids 需要删除的客户端用户主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteUmClientUserByIds(List<String> ids) {
        umAttrDataMapper.deleteByQuery(QueryWrapper.create().in(UmAttrData::getUserId, ids));
        return umClientUserMapper.deleteBatchByIds(ids);
    }

    /**
     * 删除客户端用户信息
     *
     * @param id 客户端用户主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteUmClientUserById(String id) {
        umAttrDataMapper.deleteByQuery(QueryWrapper.create().eq(UmAttrData::getUserId, id));
        return umClientUserMapper.deleteById(id);
    }

    /**
     * 新增用户属性值信息
     *
     * @param umClientUser 客户端用户对象
     */
    public void insertUmAttrData(UmClientUser umClientUser) {
        List<UmAttrData> umAttrDataList = umClientUser.getAttrDataList();
        String id = umClientUser.getId();
        if (!CollectionUtils.isEmpty(umAttrDataList)) {
            for (UmAttrData umAttrData : umAttrDataList) {
                umAttrData.setUserId(id);
            }
            umAttrDataMapper.insertBatch(umAttrDataList);
        }
    }

    @Override
    public int focus(String id) {
        return umUserFocusMapper.insert(new UmUserFocus(SecurityUtils.getUserId(), id));
    }

    @Override
    public int focusCancel(String id) {
        return umUserFocusMapper.deleteByQuery(QueryWrapper.create().eq(UmUserFocus::getUserId, SecurityUtils.getUserId()).eq(UmUserFocus::getFocusId, id));
    }

    @Override
    public Map<Object, Object> focusCount(String userId) {
        List<Map<String, Object>> list = umUserFocusMapper.focusCount(userId);
        Map<Object, Object> map = new HashMap<>();
        for (Map<String, Object> obj : list) {
            map.put(obj.get("type"), obj.get("count"));
        }
        return map;
    }

    @Override
    public Page<UmClientUser> focusList(String userId, String key, String type, PageQuery pageQuery) {
        QueryWrapper queryWrapper = QueryWrapper.create().orderBy(pageQuery.getOrderByColumn(), pageQuery.isAsc());
        if (type.equals("followers")) {// 关注我的
            queryWrapper.in(UmClientUser::getId, QueryWrapper.create().select(UM_USER_FOCUS.USER_ID).from(UM_USER_FOCUS).where(UM_USER_FOCUS.FOCUS_ID.eq(userId)));
        } else if (type.equals("following")) {// 我关注的
            queryWrapper.in(UmClientUser::getId, QueryWrapper.create().select(UM_USER_FOCUS.FOCUS_ID).from(UM_USER_FOCUS).where(UM_USER_FOCUS.USER_ID.eq(userId)));
        } else if (type.equals("mutual")) {// 相互关注
            queryWrapper.in(UmClientUser::getId, QueryWrapper.create().select(UM_USER_FOCUS.USER_ID).from(UM_USER_FOCUS).where(UM_USER_FOCUS.FOCUS_ID.eq(userId).and(UM_USER_FOCUS.USER_ID.in(QueryWrapper.create().select(UM_USER_FOCUS.FOCUS_ID).from(UM_USER_FOCUS).where(UM_USER_FOCUS.USER_ID.eq(userId))))));
        }
        SubQw subQw = getSubQw(key, null);
        if (subQw.flag()) {
            queryWrapper.in("id", subQw.subQueryWrapper());
        }
        return umClientUserMapper.paginateWithRelations(pageQuery.build(), queryWrapper);
    }

    @Override
    public List<UmClientUser> matchFullScoreDtoList(String userId, int start, int limit) {
        /*依据id构建执行驱动*/
        MatcherDrive matcherDrive = buildMatcherDriveById(userId);
        /*执行*/
        List<MatchScoreDto> matchScoreDtos = matcherDrive.invoke(start, limit);
        /*计算总分*/
        double v = matcherDrive.totalScore();
        matchScoreDtos.forEach(o -> o.setScore(o.getScore() / v * 100));
        return buildUmClientUser(matchScoreDtos);
    }

    @Override
    public List<UmClientUser> matchSimpleScoreDtoList(String userId, int start, int limit) {
        /*依据id构建执行驱动*/
        MatcherDrive matcherDrive = buildMatcherDriveById(userId);
        /*执行*/
        List<MatchScoreDto> matchScoreDtos = matcherDrive.invoke(start, limit);
        return buildUmClientUser(matchScoreDtos);
    }

    private List<UmClientUser> buildUmClientUser(List<MatchScoreDto> matchScoreDtos) {
        Map<String, MatchScoreDto> scoreDtoMap = matchScoreDtos.stream().collect(Collectors.toMap(MatchScoreDto::getUserId, Function.identity()));
        List<UmClientUser> umClientUsers = this.queryChain()
                .in(UmClientUser::getId, scoreDtoMap.keySet())
                .list();
        umClientUsers.forEach(o -> o.setMatchDegree((int) scoreDtoMap.get(o.getId()).getScore()));
        return umClientUsers;
    }

    private MatcherDrive buildMatcherDriveById(String userId) {
        /*构建条件*/
        List<UmAttrData> list = umAttrDataService.queryChain()
                .select()
                .from(UmAttrData.class)
                .eq(UmAttrData::getUserId, userId)
                .and(o -> {
                    o.eq(UmAttrData::getIsStandard, 1)
                            .or(UmAttrData::getAttrCode).eq(Constant.SEX_CODE);
                }).list();
        Map<String, UmAttrData> attrMap = list.stream().collect(Collectors.toMap(UmAttrData::getAttrCode, o -> o));
        String sex = attrMap.get(Constant.SEX_CODE).getAttrValue();
        attrMap.remove(Constant.SEX_CODE);

        if (Constant.MAN.equals(sex)) {
            sex = Constant.WOMAN;
        } else {
            sex = Constant.MAN;
        }
        /*构建执行驱动*/
        MatcherDrive matcherDrive = matcherDriveFactory.buildMatcherDrive(attrMap.values(), sex);
        return matcherDrive;
    }
}
